import * as THREE from '../../libs/three.min.js'
import { OrbitControls } from '../../libs/jsm/controls/OrbitControls'
import * as BufferGeometryUtils from '../../libs/jsm/BufferGeometryUtils'

const { windowWidth, windowHeight, pixelRatio, } = wx.getSystemInfoSync();
let canvas, scene, renderer, camera, controls ,props, clickPos, clickMarkMesh;
const hp = Math.PI * 0.5;
const pointers = [];
var selectedObject = null;
var changeId = 0;

export default (_canvas ,app) => {
  canvas = _canvas;
  _canvas.addEventListener = function() {
  // console.log("addEventListener", arguments);
  }
  // 设置画布大小
  canvas.width = windowWidth * pixelRatio;
  canvas.height = windowHeight * pixelRatio;
  canvas.clientHeight = canvas.height
  canvas.clientWidth = canvas.width;
  canvas.style = {} 
  canvas.style.width = windowWidth * pixelRatio;
  canvas.style.height = windowHeight * pixelRatio; 
  console.log("_canvas", windowWidth, windowHeight, pixelRatio);

  props = new THREE.Group();
  const touchStart = new THREE.Vector3();
  const moveStart = new THREE.Vector3();
  const moveTarget = new THREE.Vector3();
  const raycaster = new THREE.Raycaster();
  const offset = new THREE.Vector3();
  const loader = new THREE.TextureLoader(undefined, canvas);
  const step = 0.05;

  initRenender(); // 初始化渲染器
  initCamera(); // 初始化相机
  initScene(); // 初始化场景
  initControl(); // 初始化控制器
  initGeometrys() // 初始化物体

  // console.log('THREE',THREE);

  function initRenender() {
    renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
    renderer.setSize(windowWidth * pixelRatio, windowHeight * pixelRatio);
  }

  function initScene() {
    scene = new THREE.Scene();
  }

  function onTouchStart (e) {
    const changedTouches = e.changedTouches;
    if ( changedTouches[0].identifier == 0 ) {
      touchStart.set( changedTouches[0].x, changedTouches[0].y, Date.now());
    }
  }

  function onTouchEnd (e) {
    const changedTouches = e.changedTouches;
    const touches = e.touches;
    if (changedTouches[0].identifier == 0 && touches.length == 0) {
      if (changedTouches[0].x == touchStart.x && changedTouches[0].y == touchStart.y && Date.now() - touchStart.z < 500) {
        intersections(new THREE.Vector2(touchStart.x, touchStart.y));
      }
    }
  }
  function moveCameraTo() {
    offset.subVectors(moveTarget, controls.target);
    if (offset.length() > step) offset.setLength(step);
    controls.target.add(offset);
    camera.position.add(offset);
    if (offset.length() > 0.001)  canvas.requestAnimationFrame(moveCameraTo);
    // console.log('offset',offset,offset.length());
    controls.update();
    // changeId ++;
    // render();
  }
  function intersections (point) {
    selectedObject = null;
    point.x = ( point.x / windowWidth ) * 2 - 1;
		point.y = - ( point.y / windowHeight ) * 2 + 1;
    raycaster.setFromCamera( point, camera );
    const intersects = raycaster.intersectObjects( scene.children, true );
    var position = null;
    for(let i in intersects) if (intersects[i].object.type == 'Mesh') {
      position = intersects[i].point;
      selectedObject = intersects[i].object;
      break;
    }
    // console.log("intersections",point,intersects, position, selectedObject);
    if (position) {
      if (position.y < 2.0) position.y = 2.0;
      moveStart.copy(controls.target);
      moveTarget.copy(position);
      if (clickMarkMesh) {
        clickMarkMesh.position.x = position.x;
        clickMarkMesh.position.z = position.z;
      }
      moveCameraTo();
    }
  }
  

  function initCamera() {
    camera = new THREE.PerspectiveCamera( 90, canvas.width / canvas.height, 0.1, 100 );
    camera.up.set(0, 1, 0); // 设置相机对象的上方向是哪个轴
    camera.position.set(0.0, 2.0, 5.0);
    camera.lookAt(0,0,0);
  }
  function initControl() {
    app.globalData.onTouchStart = onTouchStart;
    app.globalData.onTouchEnd = onTouchEnd;
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableZoom = true; 
    controls.maxDistance = 50.0; 
    controls.target.z = 3.0; 
    controls.target.y = 2.0; 
    controls.update();
    // controls.addEventListener('change', function () { if (changeId < 1) render(); });
  }
  function initGeometrys() {
    const texture = loader.load( '../../libs/textures/10.png' );
    const mat = new THREE.MeshBasicMaterial({ map: texture });
    const geo = new THREE.PlaneGeometry(1, 1);
    mat.transparent = true;
    clickMarkMesh = new THREE.Mesh(geo, mat);
    clickMarkMesh.rotation.x = -hp;
    clickMarkMesh.position.y = 0.01;
    scene.add( clickMarkMesh );
    initSceneObjects();
    // 异步
    // setTimeout(() => { render() }, 200)
  }

  function initSceneObjects(list) {
    props.clear();
    const floor = loader.load( '../../libs/textures/cb.jpg' );
    floor.wrapS = THREE.RepeatWrapping;
    floor.wrapT = THREE.RepeatWrapping;
    floor.anisotropy = 4;
    floor.repeat.set( 50, 50 );
    floor.encoding = THREE.sRGBEncoding;
    var objects = [
      {name: 'Ambient', type: 'light', constructor: 'AmbientLight', params: [0x505050], position:[], rotation:[]},
      // {name: 'DirLight', type: 'light', constructor: 'DirectionalLight', params: [0x909090, 1.0], position:[10, 200, 100]},
      // {name: 'RectLight', type: 'light', constructor: 'RectAreaLight', params: [0xffffff, 1, 24, 5.2], position:[0, 3, 4],},
      {name: 'PointLight', type: 'light', constructor: 'PointLight', params: [0xd0d0d0, 1.0, 12, 1], position:[-9.0, 4, 4],},
      {name: 'PointLight', type: 'light', constructor: 'PointLight', params: [0xd0d0d0, 1.0, 12, 1], position:[+9.0, 4, 4],},
      // {name: 'PointLight', type: 'light', constructor: 'PointLight', params: [0xa0a0a0, 1, 10, 1], position:[+0.0, 3, 3],},
      {name: 'PointLight', type: 'light', constructor: 'PointLight', params: [0xffffff, 1.0, 100, 1], position:[-0.0, 50, -10],},
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[ 1.0, 7.0, - 7.0], target:[ 4.0,3.5,- 7.0] },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[ 1.0, 7.0, -10.5], target:[ 4.0,3.5,-10.5] },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[ 1.0, 7.0, -14.0], target:[ 4.0,3.5,-14.0] },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[ 1.0, 7.0, -17.5], target:[ 4.0,3.5,-17.5] },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[ 2.0, 7.0, -16.0], target:[ 2.0,3.6,-19.5] },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.7, 10.0, hp * 0.19, 0.9], position:[-2.0, 7.0, -16.0], target:[-2.0,3.6,-19.5] },
      {name: 'RectLight', type: 'light', constructor: 'RectAreaLight', params: [0xffffff, 0.6, 6.0, 3.0], position:[-12, 3, -16],rotation:[0,hp,0]},
      {name: 'RectLight', type: 'light', constructor: 'RectAreaLight', params: [0xffffff, 0.6, 9.0, 3.0], position:[-12, 3, -32],rotation:[0,hp,0]},
      {name: 'RectLight', type: 'light', constructor: 'RectAreaLight', params: [0xffffff, 0.9, 2.0, 6.0], position:[- 2, 5.5, -6],rotation:[-hp,0,0]},
      {name: 'TopLight', type: 'mesh', 
        geo: [  
          {constructor: 'CylinderGeometry', params: [0.2, 0.2, 0.8, 32, 1, false], position:[0, 6.8, -10], rotation:[0,0,0] } ,
          {constructor: 'CylinderGeometry', params: [0.2, 0.2, 0.8, 32, 1, false], position:[-8, 6.8, -20], rotation:[0,0,0] } ,
          {constructor: 'CylinderGeometry', params: [0.2, 0.2, 0.8, 32, 1, false], position:[-8, 6.8, -30], rotation:[0,0,0] } 
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0x202030, roughness: 1.0} }, 
      },
      {name: 'TopLightCircle', type: 'mesh', 
        geo: [  
          {constructor: 'CircleGeometry', params: [0.18, 32], position:[0, 6.39, -10], rotation:[hp,0,0] },
          {constructor: 'CircleGeometry', params: [0.18, 32], position:[-8, 6.39, -20], rotation:[hp,0,0] },
          {constructor: 'CircleGeometry', params: [0.18, 32], position:[-8, 6.39, -30], rotation:[hp,0,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xffffff, roughness: 1.0, emissive: 0xffffff} }, 
      },
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.8, 10.0, hp * 0.5, 0.5], position:[ 0.0, 6.0, -10.0], target:[ 0.0,0.0,-10.0]},
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.8, 10.0, hp * 0.5, 0.5], position:[-8.0, 6.0, -20.0], target:[-8.0,0.0,-20.0]},
      {name: 'SpotLight', type: 'light', constructor: 'SpotLight', params: [0xffffff, 0.8, 10.0, hp * 0.5, 0.5], position:[-8.0, 6.0, -30.0], target:[-8.0,0.0,-30.0]},
      {name: 'Ground', type: 'mesh', 
        geo: [  {constructor: 'PlaneGeometry', params: [100.0, 100.0, 50, 50], position:[0,0,0], rotation:[-hp,0,0] }  ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xa0a0a0, roughness: 1.0, map: floor} }, 
      },
      {name: 'OutWall', type: 'mesh', 
        geo: [ 
          {constructor: 'BoxGeometry', params: [10.0, 6.0, 0.1], position:[- 9.0, 2.5,-0.06], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.0, 6.0, 0.1], position:[+ 9.0, 2.5,-0.06], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.0, 1.0, 2.0], position:[+ 0.0,6.41, -1.8], rotation:[0,-0.2,0] },
          {constructor: 'BoxGeometry', params: [ 0.1, 7.0,10.0], position:[-4.05, 3.5, -5.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.1, 7.0,20.0], position:[+4.05, 3.5,-10.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.0, 7.0, 0.1], position:[- 9.0, 3.5,-10.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 8.0, 7.0, 0.1], position:[+ 0.0, 3.5,-20.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.1, 7.0,30.0], position:[-14.0, 3.5,-25.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.1, 7.0,20.0], position:[- 3.9, 3.5,-30.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.0, 7.0, 0.1], position:[- 9.0, 3.5,-40.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.0, 7.0, 1.0], position:[-14.0, 3.5,-24.0], rotation:[0,0,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xd0d0d0} }, 
        position:[], rotation:[]
      },
      {name: 'TopWall', type: 'mesh', 
        geo: [ 
          {constructor: 'PlaneGeometry', params: [ 8.2, 20.1], position:[- 0.0,6.91,-11.5], rotation:[hp,0,0] },
          {constructor: 'PlaneGeometry', params: [12.2, 30.2], position:[- 8.0,6.90,-25.1], rotation:[hp,0,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0x88f0ff} }, 
        position:[], rotation:[]
      },
      {name: 'CornerBar', type: 'mesh', 
        geo: [ 
          {constructor: 'BoxGeometry', params: [ 0.4, 0.4, 18.0], position:[+ 3.81,6.10,-11.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.4, 0.4,  8.0], position:[- 3.81,6.10, -6.4], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.4, 0.4,  0.4], position:[- 8.81,6.10,-10.2], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 8.4, 0.4,  0.4], position:[- 0.20,6.10,-19.8], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.4, 0.4, 30.0], position:[-13.80,6.10,-25.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 0.4, 0.4, 20.0], position:[- 4.20,6.10,-30.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [10.0, 0.4,  0.4], position:[- 9.00,6.10,-39.8], rotation:[0,0,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xffffff} }, 
        position:[], rotation:[]
      },
      {name: 'Table', type: 'mesh', 
        geo: [ 
          {constructor: 'BoxGeometry', params: [ 4.0, 0.5,  1.4], position:[- 9.00, 0.40,-15.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.4, 0.5,  4.2], position:[- 9.00, 0.40,-20.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.4, 0.5,  4.2], position:[- 9.00, 0.40,-27.0], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.4, 0.5,  4.2], position:[- 9.00, 0.40,-35.0], rotation:[0,0,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xffffff} }, 
        position:[], rotation:[]
      },
      {name: 'goodsL0', type: 'mesh', 
        geo: [
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.00, 3.20, - 4.0], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.00, 3.20, - 7.5], rotation:[0,hp,0] }, 
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[+ 4.00, 3.20, - 7.0], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[+ 4.00, 3.20, -10.5], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[+ 4.00, 3.20, -14.0], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[+ 4.00, 3.20, -17.5], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 2.00, 3.20, -19.9], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[+ 2.00, 3.20, -19.9], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 6.00, 3.20, -10.1], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 9.50, 3.20, -10.1], rotation:[0,0,0] },
          {constructor: 'BoxGeometry', params: [ 5.8, 2.5,  0.1], position:[-13.90, 3.20, -16.1], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 9.8, 2.5,  0.1], position:[-13.90, 3.20, -32.1], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.10, 3.20, -22.0], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.10, 3.20, -25.5], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.10, 3.20, -29.0], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.10, 3.20, -32.5], rotation:[0,hp,0] },
          {constructor: 'BoxGeometry', params: [ 1.8, 2.5,  0.1], position:[- 4.10, 3.20, -36.0], rotation:[0,hp,0] },
        ],
        mat: {constructor: 'MeshStandardMaterial', params: {color: 0xffffff} }, 
        position:[], rotation:[]
      },
      
    ];
    if (list && list.length > 0 && list[0].type) objects = list;
    let createLight = function (opt) {
      const light = new THREE[opt.constructor](... opt.params);
      if(opt.target) {
        const targetObject = new THREE.Object3D();
        targetObject.position.set(... opt.target);
        scene.add(targetObject);
        light.target = targetObject;
      }
      return light;
    }
    let createMesh = function (opt) {
      var geometry = null;
      var material = null;
      var mesh = null;
      const matrix = new THREE.Matrix4();
      const geos = opt.geo;
      const geometriesDrawn = [];
      for (let i = 0; i < geos.length; i++) {
        const position = new THREE.Vector3();
        const rotation = new THREE.Euler();
        const scale = new THREE.Euler(1.0, 1.0, 1.0);
        const quaternion = new THREE.Quaternion();
        var geo = new THREE[geos[i].constructor]( ...geos[i].params );
        if (geos[i].position && geos[i].position.length === 3) {
          position.set( ... geos[i].position);
        }
        if (geos[i].rotation && geos[i].rotation.length === 3) {
          rotation.set( ... geos[i].rotation);
          quaternion.setFromEuler( rotation );
        }
        matrix.compose( position, quaternion, scale );
        geo.applyMatrix4( matrix );
        geometriesDrawn.push( geo );
      }
      geometry = BufferGeometryUtils.mergeBufferGeometries( geometriesDrawn );
      if (opt.mat && opt.mat.constructor) {
        material = new THREE[opt.mat.constructor]( opt.mat.params );
      }
      if (geometry && material) mesh = new THREE.Mesh(geometry, material);
      // console.log("createMesh",geometry, material, mesh );
      return mesh;
    }
    
    for(let i = 0, il = objects.length; i < il; i++) {
      let obj = null;
      if (objects[i].type == 'light') obj = createLight(objects[i]);
      if (objects[i].type == 'mesh')  obj = createMesh(objects[i]);
      if (objects[i].position && objects[i].position.length == 3) obj.position.set( ... objects[i].position )
      if (objects[i].rotation && objects[i].rotation.length == 3) obj.rotation.set( ... objects[i].rotation )
      if(obj && !objects[i].hidden) {
        if (objects[i].name) obj.name = objects[i].name;
        props.add( obj );
      }
      // console.log('obj',objects[i].name, obj);
    }
    
    scene.add( props );
  }

  var lastDraw = Date.now();
  var now = Date.now();
  function render() {
    // renderer.render(scene, camera);
    // if (changeId > 0) changeId --;
    now = Date.now();
    if (now - lastDraw > 20) {renderer.render(scene, camera); lastDraw = now; } 
    canvas.requestAnimationFrame(render);
  }
  // const interval = setInterval(function (){ if (Date.now() - lastDraw > 1000)  render();},1000);
  render();
}